package jcu.sal.common;

import java.io.Serializable;

import jcu.sal.common.agents.SALAgent;
import jcu.sal.common.exceptions.SensorControlException;

/**
 * Objects of this class encapsulate the result of the execution of a command on a sensor.
 * The result can be retrieved using one of the <code>get*</code> methods. If a response object is part of
 * a data stream, usually obtained from a callback method, the <code>get*</code> methods may raise a
 * {@link SensorControlException}, thrown by the agent to indicate an error of some sort (stream terminated,
 * error getting reading, ...). The <code>getCause()</code> method invoked on the exception will show the
 * source of the error.
 * @author gilles
 *
 */
public class Response implements Serializable {
	private static final long serialVersionUID = -4090794353146528167L;
	private byte[] b;
	private StreamID sid;
	private SensorControlException exception;
	private long timeStamp;
	//private SALAgent agent;
	
	/**
	 * This method builds a new response with data, and no exception
	 * @param bb the data
	 * @param sid the stream id it belongs to
	 */
	public Response(byte[] bb, StreamID sid) {
		timeStamp = System.currentTimeMillis();
		this.sid = sid;
		exception = null;
		if(bb==null)
			b= new byte[0];
		else
			b = bb;
	}
	
	/**
	 * This constructor builds a response object with either the error or the end flag set. It is only intended to be used
	 * by streaming threads returning a response via a callback method 
	 * @param sid the stream id
	 * @param cid the command id of the command which generated this reponse
	 * @param e whether there was an error or not (normal end of stream)
	 */
	public Response(StreamID sid, SensorControlException e){
		this(null, sid);
		b=null;
		exception = e;
	}
	
	/**
	 * This method returns the sensor identifier of the sensor which generated this response
	 * @return the sensor identifier of the sensor which generated this response
	 */
	public String getSID() {
		return sid.getSID();
	}
	
	/**
	 * This method returns the command identifier of the command which generated this response
	 * @return the sensor identifier of the sensor which generated this response
	 */
	public int getCID() {
		return Integer.parseInt(sid.getCID());
	}
	
	/**
	 * This method returns the raw data from the sensor as a byte array.
	 * @return the raw data from the sensor 
	 * @throws SensorControlException if there was an error getting the raw data at the sensor
	 */
	public byte[] getBytes() throws SensorControlException {
		if(hasException())
			throw exception;
		return b;
	}
	
	/**
	 * This method returns the length of the raw data from the sensor.
	 * @return the raw data from the sensor 
	 * @throws SensorControlException if there was an error getting the raw data at the sensor
	 */
	public int getLength() throws SensorControlException{
		return getBytes().length;
	}
	
	/**
	 * This method returns the raw data from the sensor as a string
	 * @return the raw data from the sensor as a string
	 * @throws SensorControlException if there was an error getting the raw data at the sensor
	 */
	public String getString() throws SensorControlException {
		return new String(getBytes());
	}
	
	/**
	 * This method returns the raw data from the sensor as an integer
	 * @return the raw data from the sensor as an integer
	 * @throws SensorControlException if there was an error getting the raw data at the sensor
	 */
	public int getInt() throws SensorControlException {
		return Integer.parseInt(getString());
	}
	
	/**
	 * This method returns the raw data from the sensor as a float.
	 * @return the raw data from the sensor as a float.
	 * @throws SensorControlException if there was an error getting the raw data at the sensor
	 */
	public float getFloat() throws SensorControlException {
		return Float.parseFloat(getString());
	}
	
	/**
	 * This method returns a timestamp (generated by the SAL agent) at which the reading was generated.  
	 * @return a UNIX timestamp (number of milliseconds elapsed since 1 Jan 1970)
	 */
	public long getTimeStamp(){
		return timeStamp;
	}
	
	/**
	 * This method specifies whether an exception is attached to this response
	 * @return true if an exception is attached to this response.
	 */
	public boolean hasException(){
		return (b==null && exception !=null);
	}
	
	/**
	 * This method sets the {@link SALAgent} where this response originates from.
	 * Clients should not use this method.
	 * @param a the SALAgent which generated this response.
	 */
	public Response setAgentID(String id){
		sid.setAgentID(id);
		return this;
	}
	
//	/**
//	 * This method returns a reference to the {@link SALAgent} which creates this
//	 * response.
//	 * @return a reference to the SAL agent which generated this response
//	 */
//	public SALAgent getAgent(){
//		return agent;
//	}
	
	/**
	 * This method returns the {@link StreamID} this response belongs to.
	 * @return the {@link StreamID} this response belongs to.
	 */
	public StreamID getStreamID(){
		return sid;
	}
}
